package com.easylinkin.linkappapi.quality.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.easylinkin.linkappapi.common.exceptions.BusinessException;
import com.easylinkin.linkappapi.common.model.RequestModel;
import com.easylinkin.linkappapi.quality.dto.ProblemDTO;
import com.easylinkin.linkappapi.quality.entity.Problem;
import com.easylinkin.linkappapi.quality.entity.ProblemType;
import com.easylinkin.linkappapi.quality.entity.QualityInspection;
import com.easylinkin.linkappapi.quality.entity.QualityQuestionInfo;
import com.easylinkin.linkappapi.quality.mapper.ProblemMapper;
import com.easylinkin.linkappapi.quality.mapper.ProblemTypeMapper;
import com.easylinkin.linkappapi.quality.mapper.QualityInspectionMapper;
import com.easylinkin.linkappapi.quality.mapper.QualityQuestionInfoMapper;
import com.easylinkin.linkappapi.quality.service.ProblemService;
import com.easylinkin.linkappapi.security.context.LinkappUserContextProducer;
import com.easylinkin.linkappapi.tenant.entity.LinkappTenant;
import com.easylinkin.linkappapi.tenant.sevice.LinkappTenantService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import javax.annotation.Resource;
import java.util.*;
import java.util.function.Predicate;
import java.util.stream.Collectors;

/**
 * <p>
 * 闸机表 服务实现类
 * </p>
 *
 * @author TongJie
 * @since 2022-04-13
 */
@Service
@Slf4j
public class ProblemServiceImpl extends ServiceImpl<ProblemMapper, Problem> implements
    ProblemService {

  @Resource
  private LinkappUserContextProducer linkappUserContextProducer;

  @Autowired
  private ProblemTypeMapper problemTypeMapper;
  @Autowired
  private QualityInspectionMapper qualityInspectionMapper;
  @Autowired
  private QualityQuestionInfoMapper questionInfoMapper;

  @Resource
  private LinkappTenantService linkappTenantService;

  @Value("${edu.apiUrl}")
  private String url;

  /**
   * 增加
   * @param problem
   */
  @Override
  public void insert(Problem problem) {
    /**
     * 验证重复
     */
//    this.checkExist(problem);
    //设置全名，id路径
    this.setFull(problem);
    //设置基本属性
    this.setBase(problem);
    //设置排序
    problem.setOrder(1);
    QueryWrapper<Problem> queryWrapper = new QueryWrapper<>();
    queryWrapper.eq("tenant_id_",problem.getTenantId())
        .eq("problem_type_id_",problem.getProblemTypeId());
    List<Problem> problems = baseMapper.selectList(queryWrapper);
    problems.stream().max(Comparator.comparingInt(Problem::getOrder))
        .ifPresent(p -> problem.setOrder(p.getOrder()+1));
    this.save(problem);
  }


  @Override
  public void addFromEnterprise(Problem problem) {
    //查找问题类别
    ProblemType problemType = problemTypeMapper.selectById(problem.getProblemTypeId());
    Assert.notNull(problemType, "问题类别不存在");

    Assert.isTrue(problemType.getLevel()!=null && problemType.getLevel().equals(2),"只能在第二级类别下建问题内容");
    problem.setFullName(problemType.getFullName() + "/" + problem.getContent());

    problem.setModifyTime(new Date());
    problem.setCreateTime(new Date());

    validParamRequired(problem);
    validParamFormat(problem);
    validRepeat(problem);

    //设置排序
    problem.setOrder(1);
    QueryWrapper<Problem> queryWrapper = new QueryWrapper<>();
    queryWrapper.isNull("tenant_id_")
            .eq("problem_type_id_", problem.getProblemTypeId());

    List<Problem> problems = baseMapper.selectList(queryWrapper);
    problems.stream().max(Comparator.comparingInt(Problem::getOrder))
            .ifPresent(p -> problem.setOrder(p.getOrder() + 1));
    this.save(problem);
  }
  /**
   * 模板-校验重复
   */
  private void validRepeat(Problem problem) {
    QueryWrapper<Problem> queryWrapper = new QueryWrapper<>();
    queryWrapper.eq("full_name_", problem.getFullName());
    queryWrapper.isNull("tenant_id_");
    List<Problem> list = baseMapper.selectList(queryWrapper);
    if (list.size() == 0) {
      return;
    }
    if (list.size() > 1) {
      throw new BusinessException("名称有重复");
    }
    if (ObjectUtils.isEmpty(problem.getId())) {
      throw new BusinessException("名称已存在");
    }
    if (!problem.getId().equals(list.get(0).getId())) {
      throw new BusinessException("名称已存在");
    }
  }


  /**
   * 校验参数必填
   */
  private void validParamRequired(Problem problem) {
    Assert.notNull(problem, "参数为空");
    Assert.isTrue(ObjectUtils.isNotEmpty(problem.getContent()), "名称为空");
    Assert.isTrue(ObjectUtils.isNotEmpty(problem.getProblemTypeId()), "父id为空");
  }

  /**
   * 校验参数格式
   */
  private void validParamFormat(Problem problem) {
    Assert.isTrue(problem.getContent() == null || problem.getContent().length() <= 300,
            "名称超长");
  }

  /**
   * 设置全名，id路径
   * @param problem
   */
  private void setFull(Problem problem) {
    //查找问题类别
    ProblemType problemType = problemTypeMapper.selectById(problem.getProblemTypeId());
    Optional.ofNullable(problemType).ifPresent(p ->{
      problem.setFullId(p.getParentId()+"/"+p.getId());
      problem.setFullName(p.getFullName()+"/"+problem.getContent());
    });
  }

  /**
   * 根据id编辑
   * @param problem
   */
  @Override
  public void updateOne(Problem problem) {
    /**
     * 验证重复
     */
//    this.checkExist(problem);
    //设置全名，id路径
    this.setFull(problem);
    //设置基本属性
    this.setBase(problem);
    this.updateById(problem);
  }

  /**
   * @Description: 根据条件，查询
   * @author kan yuanfeng
   * @date 2020/11/04 11:42
   */
  @Override
  public List<Problem> queryList(Problem problem) {
    QueryWrapper<Problem> queryWrapper = new QueryWrapper<>();
    queryWrapper.eq("problem_type_id_",problem.getProblemTypeId())
        .eq("tenant_id_",linkappUserContextProducer.getNotNullCurrent().getTenantId())
        .orderByAsc("order_").orderByDesc("modify_time_");
    List<Problem> problems = baseMapper.selectList(queryWrapper);
    return problems;
  }


  @Override
  public List<Problem> listFromEnterprise(Problem problem) {
    QueryWrapper<Problem> queryWrapper = new QueryWrapper<>();
    queryWrapper
            .isNull("tenant_id_");
    if (problem.getProblemTypeId() != null) {
      ProblemType problemType = problemTypeMapper.selectById(problem.getProblemTypeId());
      if (problemType != null) {
        queryWrapper.likeRight("full_name_", problemType.getFullName() + "/");
      }else{
        return Collections.emptyList();
      }
    }
    queryWrapper.orderByDesc("create_time_");
    List<Problem> problems = baseMapper.selectList(queryWrapper);
    return problems;
  }

  /**
   * @Description: 启用/禁用
   * @author kan yuanfeng
   * @date 2020/11/04 11:42
   */
  @Override
  public void changeStatus(Problem problem) {
    UpdateWrapper<Problem> updateWrapper = new UpdateWrapper<>();
    updateWrapper.in("id",problem.getIds())
        .set("disable_",problem.getDisable());
    baseMapper.update(null,updateWrapper);
  }

  @Override
  public void changeStatusFromEnterprise(Problem problem) {
    UpdateWrapper<Problem> updateWrapper = new UpdateWrapper<>();
    updateWrapper.in("id", problem.getIds()).isNull("tenant_id_")
            .set("disable_", problem.getDisable()).set("modify_time_", new Date());
    baseMapper.update(null, updateWrapper);
  }

  /**
   * @Description: 启用/禁用
   * @author kan yuanfeng
   * @date 2020/11/04 11:42
   */
  @Override
  public void changeOrder(ProblemDTO problemDTO) {
    //获取原来的数据
    synchronized(ProblemServiceImpl.class){
      String tenantId = linkappUserContextProducer.getNotNullCurrent().getTenantId();
      Problem oldProblem = baseMapper.selectById(problemDTO.getId());
      Integer order = oldProblem.getOrder();
      if (problemDTO.isOrderFlag()){
        //挤下来的降序
        QueryWrapper<Problem> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("tenant_id_",tenantId)
            .eq("problem_type_id_",oldProblem.getProblemTypeId())
            .eq("order_",order-1);
        List<Problem> problemList = baseMapper.selectList(queryWrapper);
        if (null != problemList && problemList.size() > 0){
          Problem problem = problemList.get(0);
          problem.setOrder(order);
          baseMapper.updateById(problem);
        }
        //升序
        oldProblem.setOrder(order-1);
        baseMapper.updateById(oldProblem);
      }else {
        //挤下来的升序
        QueryWrapper<Problem> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("tenant_id_",tenantId)
            .eq("problem_type_id_",oldProblem.getProblemTypeId())
            .eq("order_",order+1);
        List<Problem> problemList = baseMapper.selectList(queryWrapper);
        if (null != problemList && problemList.size() > 0){
          Problem problem = problemList.get(0);
          problem.setOrder(order);
          baseMapper.updateById(problem);
        }
        //降序
        oldProblem.setOrder(order+1);
        baseMapper.updateById(oldProblem);
      }
    }
  }

  /**
   * 验证问题是否被引用
   */
  @Override
  public Boolean check(Integer id) {
    //验证是否被巡检记录引用
    Map<String, Object> map = new HashMap<>();
    map.put("problem_id_",id);
    List<QualityInspection> list = qualityInspectionMapper.selectByMap(map);
    //验证是否被问题引用
    map.clear();
    map.put("question_describe_id",id);
    map.put("delete_state",1);
    List<QualityQuestionInfo> infos = questionInfoMapper.selectByMap(map);
    return list.size() > 0 || infos.size()>0;
  }

  @Override
  public IPage<Problem> queryListByPage(RequestModel<Problem> requestModel) {
    Page page = requestModel.getPage();
    Problem problem = requestModel.getCustomQueryParams();
    //项目id 过滤
    problem.setTenantId(linkappUserContextProducer.getNotNullCurrent().getTenantId());
    IPage<Problem> problemIPage = baseMapper.queryListByPage(page, problem);
    return problemIPage;
  }

  /**
   * 设置基本属性
   * @param problem
   */
  private void setBase(Problem problem) {
    problem.setModifyTime(new Date());
    problem.setModifyId(linkappUserContextProducer.getCurrent().getId());
    //没有id就是新增,有就是编辑
    if (null == problem.getId()){
      problem.setCreatorId(linkappUserContextProducer.getCurrent().getId());
      problem.setCreateTime(new Date());
      problem.setTenantId(linkappUserContextProducer.getNotNullCurrent().getTenantId());
    }
  }


  @Override
  public void updateFromEnterprise(Problem problem) {
    Assert.notNull(problem.getId(), "id不能为空");
    Assert.notNull(problem.getProblemTypeId(), "getProblemTypeId 不能为空");
    ProblemType problemType = problemTypeMapper.selectById(problem.getProblemTypeId());

    problem.setFullName(problemType.getFullName() + "/" + problem.getContent());
    validRepeat(problem);
    validParamFormat(problem);

    Calendar calendar = Calendar.getInstance();
    problem.setModifyTime(calendar.getTime());

    UpdateWrapper<Problem> wrapper = new UpdateWrapper<>();
    wrapper.eq("id", problem.getId());

    baseMapper.update(problem, wrapper);
  }

  @Override
  public void deleteFromEnterprise(Problem problem) {
    if (ObjectUtils.isNotEmpty(problem.getIds())) {
      QueryWrapper<Problem> queryWrapper = new QueryWrapper<>();
      queryWrapper.in("id", problem.getIds());
      baseMapper.delete(queryWrapper);
    }
  }

  @Override
  public void synchronizeData(Integer add, Integer cover) {
    // 项目级 刷数据脚本+用到隐患 的其他业务
    // 其他业务表 用的 app_problem 的需要 加租户隔离 tenant_id
    // 项目级 租户隔离

    try {
      String tenantId = linkappUserContextProducer.getNotNullCurrent().getTenantId();
      LinkappTenant tenant = linkappTenantService.getOneById(tenantId);
      List<Integer> needUpdateIds = syncProblemType(add, cover, tenantId, tenant);
      if (ObjectUtils.isNotEmpty(needUpdateIds)) {
        problemTypeMapper.updateOfSync(needUpdateIds);
      }

      List<Integer> needUpdateIds2 = syncProblem(add, cover, tenantId, tenant);
      if (ObjectUtils.isNotEmpty(needUpdateIds2)) {
        baseMapper.updateOfSync(needUpdateIds2);
      }

    } catch (Exception e) {
      log.error("同步隐患库报错", e);
    }
  }


  // 同时考虑 full id 和 full name 同步 如果 full id 本地不存在 单 fullname 相同 则忽略
  private List<Integer> syncProblemType(Integer add, Integer cover, String tenantId, LinkappTenant tenant) {

    LinkedList<Integer> needUpdateIds = new LinkedList<>();

    //查询所有的类型 租户id 为空的
    QueryWrapper<ProblemType> q1 = new QueryWrapper<>();
    q1.isNull("tenant_id_");
    List<ProblemType> allTypes = problemTypeMapper.selectList(q1);

    QueryWrapper<ProblemType> queryWrapper = new QueryWrapper<>();
    queryWrapper.eq("tenant_id_", tenantId);
    List<ProblemType> localList = problemTypeMapper.selectList(queryWrapper);
    Map<String, List<ProblemType>> localFullNameMap = localList.stream().collect(Collectors.groupingBy(ProblemType::getFullName));
    Map<Integer, List<ProblemType>> localSrcIdMap = localList.stream().filter(new Predicate<ProblemType>() {
      @Override
      public boolean test(ProblemType problemType) {
        return problemType != null && problemType.getSrcId() != null;
      }
    }).collect(Collectors.groupingBy(ProblemType::getSrcId));

    for (int i = 0; i < allTypes.size(); i++) {
      ProblemType problemTypeEnt =  allTypes.get(i);
      String fullName = problemTypeEnt.getFullName();

      Integer srcId = problemTypeEnt.getId();
      List<ProblemType> list = localSrcIdMap.get(srcId);
      if (ObjectUtils.isEmpty(list)) {
        // 同步新增
        if (add != null && add.equals(1)) {
          if (ObjectUtils.isNotEmpty(localFullNameMap.get(fullName))) {
            log.info("如果本地有存在的 同名称的 则忽略 不新增");
            continue;
          }
          ProblemType newProblem = new ProblemType();
          newProblem.setTenantId(tenantId);
          //如果parentId 不是0 后面需要 更新为 租户下所对应的 父类型
          newProblem.setParentId(problemTypeEnt.getParentId());
          newProblem.setFullName( problemTypeEnt.getFullName());
          newProblem.setName(problemTypeEnt.getName());
          newProblem.setLevel( problemTypeEnt.getLevel());
          Date date = Calendar.getInstance().getTime();
          newProblem.setLastPushTime(date);
          newProblem.setCreateTime(date);
          newProblem.setModifyTime(date);
          newProblem.setSrcId(problemTypeEnt.getId());
          newProblem.setIsDefault(1);

          try {
            problemTypeMapper.insert(newProblem);
            needUpdateIds.add(newProblem.getId());
          } catch (Exception e) {
            log.error("appProblemTypeService.save 同步报错：", e);
          }
        }
      } else {
        // 同步覆盖
        if (cover != null && cover.equals(1)) {
          //根据fullId 设置
          ProblemType e0 = list.get(0);
          if (e0.getFullName().equals(problemTypeEnt.getFullName())
                  && e0.getName().equals(problemTypeEnt.getName()) && e0.getLevel().equals(problemTypeEnt.getLevel())) {
            log.info("信息相同，不需要同步");
            continue;
          }
          Date date = Calendar.getInstance().getTime();
          e0.setFullName(problemTypeEnt.getFullName());
          e0.setName(problemTypeEnt.getName());
          e0.setLevel(problemTypeEnt.getLevel());
          e0.setLastPushTime(date);
          e0.setModifyTime(date);
          e0.setIsDefault(1);

          UpdateWrapper<ProblemType> updateWrapper = new UpdateWrapper();
          updateWrapper.eq("tenant_id_", tenantId);
          updateWrapper.eq("src_id_", srcId);
          try {
            problemTypeMapper.update(e0, updateWrapper);
          } catch (Exception e) {
            log.error("appProblemTypeService.update 同步报错：", e);
          }

        }
      }
    }
    return needUpdateIds;
  }

  private List<Integer> syncProblem(Integer add, Integer cover, String tenantId, LinkappTenant tenant) {
    LinkedList<Integer> needUpdateIds = new LinkedList<>();

    // 查询模板所有 问题
    QueryWrapper<Problem> q1 = new QueryWrapper<>();
    q1.isNull("tenant_id_");
    List<Problem> allProblemsEnt = baseMapper.selectList(q1);

    QueryWrapper<Problem> q2 = new QueryWrapper<>();
    q2.eq("tenant_id_", tenantId);
    List<Problem> local = baseMapper.selectList(q2);
    Map<String, List<Problem>> localFullNameMap = local.stream().collect(Collectors.groupingBy(Problem::getFullName));
    Map<Integer, List<Problem>> localSrcIdMap = local.stream().filter(new Predicate<Problem>() {
      @Override
      public boolean test(Problem problem) {
        return problem!=null && problem.getSrcId()!=null;
      }
    }).collect(Collectors.groupingBy(Problem::getSrcId));

    for (int i = 0; i < allProblemsEnt.size(); i++) {
      Problem problemEnt = allProblemsEnt.get(i);
      String fullName = problemEnt.getFullName();
      Integer srcId = problemEnt.getId();
      List<Problem> list = localSrcIdMap.get(srcId);
      if (ObjectUtils.isEmpty(list)) {
        // 同步新增
        if (add != null && add.equals(1)) {
          if (ObjectUtils.isNotEmpty(localFullNameMap.get(fullName))) {
            log.info("如果本地有存在的 同名称的隐患 则忽略 不新增");
            continue;
          }
          Problem newProblem = new Problem();
          newProblem.setTenantId(tenantId);
          //先设置为enterprise 企业的typeId 后面再更新 为对应租户下的
          newProblem.setProblemTypeId(problemEnt.getProblemTypeId());
          newProblem.setFullName(problemEnt.getFullName());
          newProblem.setLevel(problemEnt.getLevel());
          newProblem.setContent(problemEnt.getContent());
          newProblem.setChangeRequirement(problemEnt.getChangeRequirement());
          newProblem.setChangeLimit(problemEnt.getChangeLimit());
          newProblem.setDisable(problemEnt.getDisable());
          newProblem.setOrder(problemEnt.getOrder());

          Date date = Calendar.getInstance().getTime();
          newProblem.setCreateTime(date);
          newProblem.setModifyTime(date);
          newProblem.setRemark(problemEnt.getRemark());
          newProblem.setSrcId(problemEnt.getId());
          newProblem.setLastPushTime(date);
          newProblem.setIsDefault(1);

          save(newProblem);
          needUpdateIds.add(newProblem.getId());
        }
      } else {
        // 同步覆盖
        if (cover != null && cover.equals(1)) {
          //根据fullId 设置
          Problem e0 = list.get(0);
          if (e0.mainEquals(problemEnt) ) {
            log.info("隐患信息相同，不需要同步");
            continue;
          }
          e0.setFullName(problemEnt.getFullName());
          e0.setLevel(problemEnt.getLevel());
          e0.setContent(problemEnt.getContent());
          e0.setChangeRequirement(problemEnt.getChangeRequirement());
          e0.setChangeLimit(problemEnt.getChangeLimit());
          e0.setDisable(problemEnt.getDisable());
          e0.setOrder(problemEnt.getOrder());
          e0.setIsDefault(1);

          Date date = Calendar.getInstance().getTime();
          e0.setModifyTime(date);
          e0.setRemark(problemEnt.getRemark());
          e0.setLastPushTime(date);

          UpdateWrapper<Problem> updateWrapper = new UpdateWrapper();
          updateWrapper.eq("tenant_id_", tenantId);
          updateWrapper.eq("src_id_", srcId);
          getBaseMapper().update(e0, updateWrapper);
        }
      }
    }
    return needUpdateIds;
  }

}
